#include "Polygon2D.h"

Polygon2D::Polygon2D(vector<Vec2d> v){
	mVertices=v;
}

Vec2d Polygon2D::getCentroid(){
	Vec2d c(vl_0);
	if(mVertices.size()==0) return c;
	for(int i=0; i<mVertices.size(); i++){
		c+=mVertices[i];
	}
	return c/mVertices.size();
}

vector<Vec2d> Polygon2D::getVertices(){
	return mVertices;
}

// returns true if its a right turn 
bool Polygon2D::rightTurn(Vec2d v1, Vec2d v2, Vec2d v3){
	Vec2d d1, d2;
	d1=v2-v1;
	d2=v3-v2;

	double cross=d1[0]*d2[1]-d2[0]*d1[1];

	if(cross>0) return true; 
	else return false;
}
bool sortByX(Vec2d v1, Vec2d v2){return (v1[0]<v2[0]);}

vector<Vec2d> Polygon2D::sortVertices(){
	vector<Vec2d> sortlist;
	sortlist=mVertices;
	sort(sortlist.begin(), sortlist.end(), sortByX);
	return sortlist;
}

vector<Vec2d> Polygon2D::convexHull(){
	// assume clockwise clicking of points
	// lookout for right turns - positive cross products
	vector<Vec2d> hull;
	hull.clear();
	if(mVertices.size()<2) return hull;

	vector<Vec2d> sortlist = sortVertices();
	//int n=mVertices.size();
	// upper hull
	//printf("\n*** upper hull ***\n");
	hull.push_back(sortlist[0]);
	hull.push_back(sortlist[1]);
	//printf("push %lf %lf\n", sortlist[0][0], sortlist[0][1]);
	//printf("push %lf %lf\n", sortlist[1][0], sortlist[1][1]);

	for(int i=2; i<sortlist.size(); i++){
		while(1){
			if(hull.size()<2) {
				hull.push_back(sortlist[i]);
				//printf("push %lf %lf\n", sortlist[i][0], sortlist[i][1]);
				break;
			}
			else if(rightTurn(hull[hull.size()-2], hull[hull.size()-1], sortlist[i])){
				hull.push_back(sortlist[i]);
				//printf("push %lf %lf\n", sortlist[i][0], sortlist[i][1]);
				break;
			}
			else {
				//printf("pop %lf %lf\n", hull[hull.size()-1][0], hull[hull.size()-1][1]);
				hull.pop_back();
			}				
		}
	}
	// lower hull
	//printf("\n*** lower hull ***\n");
	hull.push_back(sortlist[sortlist.size()-2]);
	//printf("push %lf %lf\n", sortlist[sortlist.size()-2][0], sortlist[sortlist.size()-2][1]);

	for(int i=sortlist.size()-3; i>=0; i--){
		while(1){
			if(hull.size()<2) {
				hull.push_back(sortlist[i]);
				//printf("push %lf %lf\n", sortlist[i][0], sortlist[i][1]);
				break;
			}
			else if(rightTurn(hull[hull.size()-2], hull[hull.size()-1], sortlist[i])){
				hull.push_back(sortlist[i]);
				//printf("push %lf %lf\n", sortlist[i][0], sortlist[i][1]);
				break;
			}
			else {
				//printf("pop %lf %lf\n", hull[hull.size()-1][0], hull[hull.size()-1][1]);
				hull.pop_back();
			}				
		}
	}
	// pop the leftmost vertex -- added twice
	hull.pop_back();

	return hull;
}

void Polygon2D::inflate(double scale){
	Vec2d c = getCentroid();
	for(int i=0; i<mVertices.size(); i++){
		mVertices[i] = c + scale*(mVertices[i]-c);
	}
}

double Polygon2D::edgeDist(Vec2d p, Vec2d p0, Vec2d p1){
	double val = (p[1] - p0[1])*(p1[0] - p0[0]) - (p[0] - p0[0])*(p1[1] - p0[1]);
	return val;
}

int Polygon2D::whichSide(Vec2d p, Vec2d p0, Vec2d p1){
	return moremath::sgn(edgeDist(p, p0, p1));
}

bool Polygon2D::isInside(Vec2d p){
	// only true for convex Polygon2Ds !
	//implicitly assumes that lying on edge is considered outside
	if(mVertices.size()<2) return false;
	bool inside = true;
	int sign = whichSide(p, mVertices[mVertices.size()-1], mVertices[0]);
	for(int i=0; i<mVertices.size()-1; i++){
		if(whichSide(p, mVertices[i], mVertices[i+1])!=sign) {
			inside=false;
			break;
		}
	}
	return inside;
}

double Polygon2D::minEdgeDist(Vec2d p){
	// only true for convex Polygon2Ds !
	if(mVertices.size()<2) return -1;
	double minDist = edgeDist(p, mVertices[mVertices.size()-1], mVertices[0]);
	for(int i=0; i<mVertices.size()-1; i++){
		double dist = edgeDist(p, mVertices[i], mVertices[i+1]);
		if(minDist < dist) dist=minDist;
	}
	return minDist;
}

